import { FormRef } from '@antd/general-form'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { TableProps } from 'antd'
import useUrlState from '@ahooksjs/use-url-state';
import { ColumnType } from 'antd/lib/table'
import { ButtonType } from 'antd/lib/button'
import { TableRowSelection } from 'antd/lib/table/interface'
import {
  FilterValue,
  SorterResult,
  TableCurrentDataSource,
  TableEllipsisType
} from 'antd/lib/table/interface'
import ButtonsList from './buttonsList'

export type TableBtnConfigType<T> = {
  text: string
  renderType?: 'delete' | 'create' | 'submit' | 'download',
  type?: ButtonType
  onClick?: (selectedKeys: string[], selectedRows: Array<T>) => void
  disabled?: false
  icon?: React.ReactNode
  linkUrl?: string
  popconfirmTitle?: string
}

export type selectedItemsType<T> = {
  selectedKeys: string[]
  selectedRows: Array<T>
}
export interface ResultList<T> {
  curPage?: number
  pageNum?: number
  pageSize: number
  result?: Array<T>
  list?: Array<T>
  rows?: Array<T>
  startRow: number
  total?: number
  totalPages: number
  totalRows: number
}

export interface RequestFn<T = any, R = any> {
  (data?: T, showMsg?: boolean | string, errMsg?: boolean | string): Promise<R>
}
export type PageInfo = {
  pageNum: number
  pageSize: number
  total: number
}
type CustomSwitchType<TData> = {
  topBtns?: TableBtnConfigType<TData>[]
  openRowSelection?: boolean
}
interface SorterAndFilter {
  filters?: {
    [k: string]: FilterValue | null
  }
  sorter?: SorterResult<any>
  heightSearch?: boolean
}

export type FormatParams<TParams, FormData> = (
  data: Omit<FormData, 'heightSearch'> &
    Omit<SorterAndFilter, 'heightSearch'> &
    Omit<PageInfo, 'total'>
) => TParams
function formatData(p: any) {
  return p
}

export type SearchFormData<T> = T & SorterAndFilter

export type UseTableParams<TParams, TData, FormData> = {
  getData: RequestFn<TParams, ResultList<TData>>
  formatParams?: FormatParams<TParams, FormData>
  urlKey?: string
  defaultParams?: Record<string, any>
  tableProps?: TableProps<TData> & CustomSwitchType<TData>
}
export default <TParams, TData, FormData>({
  getData,
  formatParams = formatData,
  urlKey,
  defaultParams,
  tableProps
}: UseTableParams<TParams, TData, FormData>) => {
  const form = useRef<FormRef<SearchFormData<FormData>>>(null)
  const [pageInfo, setPageInfo] = useUrlState<PageInfo>(
    {
      pageNum: 1,
      pageSize: 10,
      total: 0
    },
    `${urlKey ?? ''}_pageInfo`
  )
  const [dataSource, setData] = useState<Array<TData>>([])
  const [loading, setLoading] = useState<boolean>(false)
  const [params, setParams] = useUrlState<SearchFormData<FormData>>(
    {} as SearchFormData<FormData>,
    `${urlKey ?? ''}_params`
  )

  const getList = useCallback(
    async ({
      pageNum = 1,
      pageSize = 10,
      filters = params.filters,
      sorter = params.sorter
    }) => {
      if (!form.current) return
      const data = form.current
        ? await form.current?.validate()
        : ({} as SearchFormData<FormData>)
      setLoading(true)
      data.filters = filters
      data.sorter = sorter
      const { heightSearch, ...p } = data
      getData(formatParams({ ...defaultParams, ...p, pageNum, pageSize }))
        .then((res) => {
          if (!res) return
          const listData: TData[] = res.list ?? res.result ?? res.rows ?? []
          if (listData.length === 0 && pageNum > 1) {
            return getList({
              pageNum: pageNum - 1,
              pageSize,
              filters,
              sorter
            })
          }
          setData(listData)
          tableProps?.rowSelection?.onChange?.([], [])
          setPageInfo({
            pageNum: res.curPage ?? res.pageNum ?? 1,
            pageSize: res.pageSize,
            total: res.totalRows ?? res.total
          })
          setParams({
            ...(form.current?.getValues() as SearchFormData<FormData>),
            filters,
            sorter
          })
          form.current?.setValue('_now_', Date.now())
          return null
        })
        .finally(() => {
          setLoading(false)
        })
    },
    [
      params.filters,
      params.sorter,
      getData,
      formatParams,
      defaultParams,
      setPageInfo,
      setParams,
      tableProps?.rowSelection
    ]
  )
  const [selectedItems, setSelectedItems] = useState<selectedItemsType<TData>>({
    selectedKeys: [],
    selectedRows: []
  })

  useEffect(() => {
    form.current?.setValues(params)
    getList({ pageNum: pageInfo.pageNum, pageSize: pageInfo.pageSize })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const transMultipButtons = useCallback((
    btns: TableBtnConfigType<TData>[],
    btnsDisabled: boolean
  ) => {
    if (btnsDisabled) {
      // 如果是禁用状态，则每项加一个disabled属性
      return btns.map((item) => {
        return {
          ...item,
          disabled: item?.disabled ?? true
        }
      })
    }
    return btns
  }, [])

  const renderInlineHeader = useMemo(() => {
    const btns = tableProps?.topBtns || []
    const mulBtnsDisabled = !selectedItems.selectedRows.length
    /* eslint-disable consistent-return */
    if (!btns?.length) return
    return (
      <ButtonsList
        buttonsConfig={
          transMultipButtons(btns, mulBtnsDisabled) as TableBtnConfigType<TData>[]
        }
        selectedItems={selectedItems}
      />
    )
  }, [tableProps?.topBtns, selectedItems, transMultipButtons])

  return useMemo(() => {
    const rowSelectionConfig = {
      onChange: (selectedKeys: string[], selectedRows: Array<TData>) => {
        setSelectedItems({ selectedKeys, selectedRows })
      },
      selectedRowKeys: selectedItems?.selectedKeys,
      checkAllPosition: 'top'
    }
    const tProps: TableProps<TsData> = {
      dataSource,
      onChange(p, filters, sorter) {
        getList({ pageNum: p.current, pageSize: p.pageSize, filters, sorter })
        setSelectedItems({ selectedKeys: [], selectedRows: [] })
      },
      rowKey: 'id',
      columnController: {
        hideTriggerButton: true
      },
      textEllipsis: tableProps?.textEllipsis ?? {
        align: {
          offset: ['50%', 15] as any
        },
        alignPoint: false
      } as TableEllipsisType,
      ...tableProps,
      topContent: tableProps?.topContent ?? renderInlineHeader,
      // 打开openRowSelection开关，或者topBtns有值, 加入预设值rowSelectionConfig
      rowSelection:
        tableProps?.openRowSelection ||
        (tableProps?.topBtns || []).some((item) => item.disabled !== false)
          ? {
              ...(rowSelectionConfig as TableRowSelection<TData>),
              ...tableProps?.rowSelection
            }
          : tableProps?.rowSelection,
      pagination: {
        total: pageInfo.total,
        current: pageInfo.pageNum,
        pageSize: pageInfo.pageSize,
        ...tableProps?.pagination
      },
      loading: loading || tableProps?.loading,
      columns: tableProps?.columns?.map((column: ColumnType<TData>) => ({
        ...column,
        render: (...args) => {
          return column?.render?.(...args) ?? args[0] ?? '-'
        },
        sortOrder:
          column.dataIndex === params.sorter?.columnKey
            ? params.sorter?.order
            : undefined,
        filteredValue: params.filters?.[column.dataIndex as string] ?? []
      }))
    }
    return {
      form,
      tableProps: tProps,
      params,
      pageInfo,
      search: {
        submit() {
          getList({ pageNum: 1, pageSize: 10 })
          setSelectedItems({ selectedKeys: [], selectedRows: [] })
        },
        refresh(pageNum = pageInfo.pageNum, pageSize = pageInfo.pageSize) {
          getList({ pageNum, pageSize })
          setSelectedItems({ selectedKeys: [], selectedRows: [] })
        },
        reset() {
          form.current?.resetFields({})
          tProps.onChange?.(
            {
              current: 1,
              pageSize: 10
            },
            {},
            [],
            {} as TableCurrentDataSource<TData>
          )
        }
      }
    }
  }, [dataSource, loading, pageInfo, tableProps, params, getList, selectedItems?.selectedKeys, renderInlineHeader])
}
